-- Summon
-- Create by panyl
-- 召唤兽对象

Summon = {
    classId = 0,
    hp     = 0,
    attack     = 0,

    -- 对象类型为召唤兽
    type = OBJECT_TYPE_SUMMON,
};
Summon.__index = Summon;

-- 构造函数
function Summon.new(classId, data)
    local self = {};
    setmetatable(self, Summon);
    self.classId = classId;
    self.dbase = Dbase.new(data);

    for key, value in pairs(data) do
        self[key] = value;
    end

    return self;
end

-- 取得该对象的描述字符串
function Summon:get_ob_id()
    return string.format("Summon:%s", tostring(self.classId));
end

-- 查找数据
function Summon:query(path, path2, default)
    if path == "classId" or path == "class_id" then
        return self.classId;
    else
        local v = self.dbase:query(path, path2, default);
        if v then
            return v;
        else
            return SummonM.query(self.classId, path);
        end
    end
end

-- 查询属性
function Summon:queryAttrib(attrib, args)
    return AttribM.queryAttrib(self, attrib, args);
end

-- 获得属性
function Summon:addAttrib(attrib, amount)
    local curValue = self.dbase:query(attrib, 0);
    curValue = curValue + amount;
    self.dbase:set(attrib, curValue);

    if "hp" == attrib or "mp" == attrib or "attack" == attrib then
        SummonM.sync_summon_data(self);
    end
end

-- 扣除属性
function Summon:costAttrib(attrib, amount)
    local curValue = self.dbase:query(attrib, 0);

    curValue = curValue - amount;
    self.dbase:set(attrib, curValue);

    SummonM.sync_summon_data(self);
end

-- 设置血量
function Summon:setHp(hp)
    self.dbase:set("hp", hp);
end

-- 当前血量
function Summon:getHp()
    return self:queryAttrib("hp");
end

-- 最大血量
function Summon:getMaxHp()
    return self:queryAttrib("max_hp");
end

-- 计算基础攻击值
function Summon:getAttack()
    return self:queryAttrib("attack");
end

-- 吸血概率
function Summon:getAbsorbRate()
    return FormulaM.invoke("CALC_SUMMON_ABSORB_RATE", self);
end

-- 命中
function Summon:getAccuracy()
    return self:queryAttrib("accuracy");
end

-- 闪避
function Summon:getDodge()
    return self:queryAttrib("dodge");
end

-- 名称
function Summon:getName()
    return self:query("name");
end

-- 获取属主
function Summon:getOwner()
    -- TODO
    return self.pos;
end

function Summon:getPos()
    return self:getOwner();
end

-- 受到伤害
function Summon:receiveDamage(damage)
    local hp = (self:query("hp") or 0) - damage;
    self:setHp(hp);

    local pos = self:getPos();

    local msg = string.format("[Summon]%s(%d)收到伤害：%d，当前hp：%d",
        self:getName(), pos, damage, hp);
    DungeonLogM.addLog(msg);


    SummonM.sync_summon_data(self);

    -- 抛出魔藤受创事件
    --EventMgr.fire(event.SUMMON_DAMAGED, {["summon"] = self, ["damage"] = damage, });

    return hp;
end

-- 死亡
function Summon:die()
    if self:getHp() > 0 then
        return false;
    end

    -- 尝试复活
    if PropM.trigger(self, "summon_revive", 1) then
        DungeonLogM.addLog("[Summon]召唤兽死亡复活。");

        return false;
    end

    DungeonLogM.addLog("[Summon]召唤兽死亡了。");

    -- 标记死亡
    self.dbase:set("is_dead", 1);

    -- 将格子设置为无效
    local pos = self:getOwner();
    local grid = DungeonM.getCurrentDungeon();
    grid[pos]:changeState(GRID_STATE_DISABLE);

    -- 触发下自爆
    PropM.trigger(ME.user, "summon_explode", self.classId, self);

    -- 死亡触发技能
    PropM.trigger(self, "summon_die_skill", 1);

    -- 抛出事件
    EventMgr.fire(event.SUMMON_DIE, { ["summon"] = self, });

    return true;
end

-- 是否已死亡
function Summon:isDead()
    -- 有死亡标志
    if 1 == self.dbase:query("is_dead") then
        return true;
    end

    return false;
end

-- 召唤兽技能
function Summon:getAllSkills()
    local skills = SummonM.query(self.classId, "skills");
    if type(skills) == "table" then
        return skills;
    end

    if type(skills) == "string" and string.len(skills) > 0 then
        -- 配置了公式
        local formulaName = skills;
        return FormulaM.invoke(formulaName, ME.user);
    end

    return skills;
end

-- 倒计时
function Summon:getCountDown()
    local round = CombatM.getRound();

    if self:isDead() then
        return -1;
    end

    -- 消失回合
    local disappear = self:query("disappear");
    if type(disappear) == "number" then
        local activeRound = self.active_round or 0;

        local lastRound = disappear + activeRound - round + 1;
        if lastRound <= 0 then
            lastRound = 1;
        end

        return lastRound;
    end

    local grid   = DungeonM.getGridByPos(self:getPos());
    if not grid or grid.type ~= GRID_TYPE_SUMMON then
        return;
    end

    local elementId = grid.element;
    local dbase = DungeonM.queryElement(elementId).dbase;
    local disappearRound = dbase.disappear or 0;
    local cycle = self:query("cycle") or 1;

    -- 一些主动技倒计时
    local keepRound;
    local propRound;
    local propNames = {"remote_magic", "remote_attack", "suicide_attack", "remote_summon"};
    for _, propName in pairs(propNames) do
        local props = PropM.fetchProps(self, propName);
        if #props > 0 then
            keepRound = tonumber(props[1][2]);

            if propName == "remote_summon" then
                propRound = self.active_round;
            end
            break;
        end
    end

    -- 主动释放技
    local skills = SummonM.getAllSkills(self) or {};
    local activeSkill;
    if #skills > 0 then
        -- TODO 取第一个
        activeSkill = skills[1];
    end

    if type(keepRound) == "number" then
        -- 宠物prop
        keepRound = keepRound;
    elseif disappearRound > 0 then
        -- 消失回合
        keepRound = disappearRound + 1;
    elseif cycle > 1 then
        -- 攻击回合，只有攻击间隔大于1轮的需要显示
        local cd = SummonM.calcPhysicCd(self);
        local actionRound = self.action or 0;
        return cd - (round - actionRound) % cd;
        -- return math.max(actionRound - round, 1);
    elseif type(activeSkill) == "number" then
        -- 主动技
        if tonumber(SummonM.calcSkillCd(self, activeSkill)) > 0 then
            return SummonM.calcSkillCd(self, activeSkill);
        else
            return;
        end
    else
        return;
    end

    local startRound = propRound or grid.openRound or 0;
    local cd = (round - startRound) % keepRound;

    return keepRound - cd;
end
